<script lang="ts" setup>
import axios, { isAxiosError } from "axios";
import {
  ElButton,
  ElDialog,
  ElForm,
  ElFormItem,
  ElInput,
  ElMessage,
} from "element-plus";
import { reactive, ref } from "vue";
import {
  BusinessStatusCode,
  type ResultContext,
} from "../../types/ResultContext";
import type { User } from "../../types/User";

/** 控制对话框的可见性。 */
const isVisble = ref(false);

/** 用户注册信息的表单。 */
const registerForm = reactive({
  username: "",
  password: "",
  confirmPassword: "",
  nickname: "",
});

/** 显示在每个字段上的错误信息。 */
const formErrors = reactive({
  username: "",
  password: "",
  confirmPassword: "",
  nickname: "",
});

/**
 * 设置表单上对应字段的错误信息。
 * @param field 要设置错误信息的字段。
 * @param message 要在表单字段上显示的错误信息，如果设置为空字符串则没有错误信息。
 */
const setError = (field: keyof typeof formErrors, message: string) => {
  formErrors[field] = message;
};

/** 清除表单上的所有错误信息。 */
const clearErrors = () => {
  formErrors.username = "";
  formErrors.password = "";
  formErrors.confirmPassword = "";
  formErrors.nickname = "";
};

/** 清除表单。 */
const clearForm = () => {
  registerForm.username = "";
  registerForm.password = "";
  registerForm.confirmPassword = "";
  registerForm.nickname = "";
  clearErrors();
};

/** 显示对话框。 */
const open = () => {
  clearForm();
  isVisble.value = true;
};

/** 隐藏对话框。 */
const close = () => {
  clearForm();
  isVisble.value = false;
};

/**
 * 表单中的`username`字段输入时的回调方法。
 * @param value 用户输入的内容。
 */
const onUsernameInput = (value: string) => {
  // 以免增加除去尾部空白符后的检测用户名重复的复杂处理，不允许用户名包含空白符。
  if (/\s/g.test(value)) {
    // 检测到空白符则将其替换为空字符串，并且在表单给出提示。
    value = value.replace(/\s/g, "");
    setError("username", "用户名不能包含空白字符");
  } else {
    // 用户没有输入空白符，则取消提示。
    setError("username", "");
  }
  registerForm.username = value;
};

/** 用户单击登录按钮后所执行的回调方法。 */
const onLoginButtonClicked = async () => {
  // 先清除原有的错误信息，表单合法性检测时，会重新为不符合要求的字段添加错误信息。
  clearErrors();

  // 表单内容的合法性检测。
  if (!registerForm.username.trim()) {
    setError("username", "请输入用户名");
    return;
  }
  if (!registerForm.nickname.trim()) {
    setError("nickname", "请输入昵称");
    return;
  }
  if (!registerForm.password.trim()) {
    setError("password", "请输入密码");
    return;
  }
  if (!registerForm.confirmPassword.trim()) {
    setError("confirmPassword", "请确认密码");
    return;
  }
  if (registerForm.password !== registerForm.confirmPassword) {
    setError("confirmPassword", "两次输入的密码不一致");
    return;
  }

  // 向后端发起注册请求。
  try {
    const response = await axios.post<ResultContext<User>>(
      "http://localhost:8080/api/auth/register",
      {
        username: registerForm.username,
        password: registerForm.password,
        nickname: registerForm.nickname,
      },
    );

    if (response.data.code === 0) {
      ElMessage.success("注册成功！请登录您的账户。");
    }
    switchToLogin();
  } catch (error) {
    if (isAxiosError(error)) {
      const result = error.response?.data as ResultContext<void>;
      const messages: Partial<Record<BusinessStatusCode, string>> = {
        [BusinessStatusCode.USER_ALREADY_EXIST]: "用户名已被占用。",
        [BusinessStatusCode.NULL_KEY_FIELD]: "用户名或密码为空。",
      };
      ElMessage.error(messages[result?.code]);
    } else {
      ElMessage.error("网络异常。");
    }
  }
};

/** 定义事件列表。 */
const emit = defineEmits(["switch-to-login"]);

/** 关闭此对话框，并且打开登录对话框。 */
const switchToLogin = () => {
  close();
  emit("switch-to-login");
};

// 向父组件暴露`open`方法。
defineExpose({ open });
</script>

<template>
  <ElDialog
    v-model="isVisble"
    title="注册"
    align-center
    :width="420"
    class="register-dialog"
    :show-close="false"
    append-to-body
  >
    <div class="register-content">
      <div class="register-header">
        <h2>创建新账户</h2>
        <p>请填写以下信息完成注册</p>
      </div>

      <ElForm class="register-form" label-position="top">
        <ElFormItem class="form-item">
          <template #label>
            <div class="form-label-wrapper">
              <span>用户名</span>
              <span class="form-error" v-if="formErrors.username">{{
                formErrors.username
              }}</span>
            </div>
          </template>
          <ElInput
            v-model="registerForm.username"
            placeholder="请输入用户名"
            size="large"
            class="register-input"
            :class="{ 'input-error': formErrors.username }"
            @input="onUsernameInput"
          />
        </ElFormItem>
        <ElFormItem class="form-item">
          <template #label>
            <div class="form-label-wrapper">
              <span>昵称</span>
              <span class="form-error" v-if="formErrors.nickname">{{
                formErrors.nickname
              }}</span>
            </div>
          </template>
          <ElInput
            v-model="registerForm.nickname"
            placeholder="请输入昵称"
            size="large"
            class="register-input"
            :class="{ 'input-error': formErrors.nickname }"
          />
        </ElFormItem>
        <ElFormItem class="form-item">
          <template #label>
            <div class="form-label-wrapper">
              <span>密码</span>
              <span class="form-error" v-if="formErrors.password">{{
                formErrors.password
              }}</span>
            </div>
          </template>
          <ElInput
            v-model="registerForm.password"
            type="password"
            placeholder="请输入密码"
            size="large"
            class="register-input"
            :class="{ 'input-error': formErrors.password }"
            show-password
          />
        </ElFormItem>
        <ElFormItem class="form-item">
          <template #label>
            <div class="form-label-wrapper">
              <span>确认密码</span>
              <span class="form-error" v-if="formErrors.confirmPassword">{{
                formErrors.confirmPassword
              }}</span>
            </div>
          </template>
          <ElInput
            v-model="registerForm.confirmPassword"
            type="password"
            placeholder="请再次输入密码"
            size="large"
            class="register-input"
            :class="{ 'input-error': formErrors.confirmPassword }"
            show-password
          />
        </ElFormItem>
      </ElForm>
    </div>

    <template #footer>
      <div class="dialog-footer">
        <ElButton class="login-link-btn" text @click="switchToLogin">
          已有账号？立即登录
        </ElButton>
        <ElButton
          type="primary"
          size="large"
          class="register-btn"
          @click="onLoginButtonClicked"
        >
          注册
        </ElButton>
      </div>
    </template>
  </ElDialog>
</template>

<style scoped>
.register-dialog {
  border-radius: 16px;
  overflow: hidden;
}

.register-dialog :deep(.el-dialog) {
  border-radius: 16px;
  box-shadow: 0 12px 48px rgba(0, 0, 0, 0.15);
}

.register-dialog :deep(.el-dialog__header) {
  padding: 0;
  border-bottom: none;
}

.register-dialog :deep(.el-dialog__title) {
  display: none;
}

.register-dialog :deep(.el-dialog__body) {
  padding: 32px 32px 24px;
}

.register-dialog :deep(.el-dialog__footer) {
  padding: 0 32px 32px;
  border-top: 1px solid #f0f0f0;
  padding-top: 24px;
}

.register-content {
  margin-bottom: 8px;
}

.register-header {
  text-align: center;
  margin-bottom: 32px;
}

.register-header h2 {
  margin: 0 0 8px 0;
  font-size: 24px;
  font-weight: 600;
  color: #333;
}

.register-header p {
  margin: 0;
  font-size: 14px;
  color: #666;
}

.register-form {
  margin-bottom: 16px;
}

.form-item {
  margin-bottom: 20px;
}

.form-item :deep(.el-form-item__label) {
  font-weight: 500;
  color: #333;
  margin-bottom: 8px;
  font-size: 14px;
  padding: 0;
}

.form-label-wrapper {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
}

.form-error {
  font-size: 12px;
  color: #f56c6c;
}

.register-input {
  border-radius: 8px;
}

.register-input :deep(.el-input__wrapper) {
  border-radius: 8px;
  box-shadow: 0 0 0 1px #dcdfe6;
  transition: all 0.2s;
}

.register-input :deep(.el-input__wrapper:hover) {
  box-shadow: 0 0 0 1px #c0c4cc;
}

.register-input :deep(.el-input__wrapper.is-focus) {
  box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.3);
}

.register-input.input-error :deep(.el-input__wrapper) {
  box-shadow: 0 0 0 1px #f56c6c;
}

.register-input.input-error :deep(.el-input__wrapper:hover),
.register-input.input-error :deep(.el-input__wrapper.is-focus) {
  box-shadow: 0 0 0 2px rgba(245, 108, 108, 0.3);
}

.dialog-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-direction: column;
  gap: 16px;
}

.login-link-btn {
  color: #666;
  font-size: 14px;
  padding: 0;
}

.login-link-btn:hover {
  color: #409eff;
}

.register-btn {
  width: 100%;
  height: 44px;
  border-radius: 8px;
  font-size: 16px;
  font-weight: 500;
  background: linear-gradient(135deg, #67c23a 0%, #85ce61 100%);
  border: none;
  box-shadow: 0 4px 12px rgba(103, 194, 58, 0.3);
  transition: all 0.2s;
}

.register-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 6px 16px rgba(103, 194, 58, 0.4);
  background: linear-gradient(135deg, #85ce61 0%, #67c23a 100%);
}

.register-btn:active {
  transform: translateY(0);
  box-shadow: 0 2px 8px rgba(103, 194, 58, 0.3);
}
</style>
